<?php
class MDispatcher extends MSingleton {
    /**
     * @var MRouter
     */
    private $_router;

    protected function __construct() {
        parent::__construct();

        $this->_router = MRouter::getInstance();
    }

    /**
     * Dispatch the current (or defined) request
     * @param MRequest $request (optional) : The request to dispatch
     */
    public function dispatch(MRequest $request = NULL) {
        if (isset($request)){
            try {
                $this->forward($request);
            } catch (Exception $exc) {
                $module = $request->getModule();
                if (isset($module)){
                    $view = new MView(NULL, NULL, NULL);
                    $response = new MResponse();
                    if ($request->isAdmin()){
                        $response->setModule(MApplication::ADMIN_MODULE);
                    } else {
                        $response->setModule($module);
                    }
                    $response->setContent($view->render('exception', array('exception'=>$exc), MD_LIB.DS.'views'));
                    $response->render();
                } else {
                    $view = new MView(NULL, NULL, NULL);
                    $response = new MResponse();
                    $response->setContent($view->render('exception', array('exception'=>$exc), MD_LIB.DS.'views'));
                    $response->render();
                }
            }
        } else {
            $request = new MRequest();
            try {
                $this->_router->route($request);
                $this->forward($request);
            } catch (Exception $exc) {
                $module = $request->getModule();
                if (isset($module)){
                    $view = new MView(NULL, NULL, NULL);
                    $response = new MResponse();
                    if ($request->isAdmin()){
                        $response->setModule(MApplication::ADMIN_MODULE);
                    } else {
                        $response->setModule($module);
                    }
                    $response->setContent($view->render('exception', array('exception'=>$exc), MD_LIB.DS.'views'));
                    $response->render();
                } else {
                    $view = new MView(NULL, NULL, NULL);
                    $response = new MResponse();
                    $response->setContent($view->render('exception', array('exception'=>$exc), MD_LIB.DS.'views'));
                    $response->render();
                }
            }
            unset($request);
        }
    }

    /**
     * Execute the controller and the action defined in the request
     * @param MRequest $request : The request to execute
     */
    public function forward(MRequest $request) {
        $modulesFolder = Mandrill::getApp()->modulesFolder;
        if (file_exists(BASE_PATH.DS.$modulesFolder.DS.$request->getModule())) {
            // Require requested Module class
            require_once BASE_PATH.DS.$modulesFolder.DS.$request->getModule().DS.$request->getModule().'.php';
            $moduleClass = MNormalizer::normalizeModuleClass($request->getModule());
            $moduleClass::setRequest($request);
            $response = new MResponse();
            $moduleClass::setResponse($response);
            if ($request->isAdmin()){
                require_once BASE_PATH.DS.$modulesFolder.DS.MApplication::ADMIN_MODULE.DS.MApplication::ADMIN_MODULE.'.php';
                MTemplate::getInstance()->setModule(MApplication::ADMIN_MODULE);
                Mandrill::getApp()->loadModuleAdmin($request->getModule());
            } else {
                Mandrill::getApp()->loadModule($request->getModule());
            }
            $path = BASE_PATH.DS.$modulesFolder.DS.$request->getModule();
            $get = $request->getGet();
            $routeParams = (!empty($get))?array_intersect_key($get, Mandrill::getApp()->routeKeys):NULL;
            if (!empty($routeParams)) {
                switch (key($routeParams)) {
                    case Mandrill::getApp()->routeKeys['page']:
                        $pageClass = isset(Mandrill::getApp()->routes['page']['class'])?Mandrill::getApp()->routes['page']['class']:'MPage';
                        $page = new $pageClass(intval($routeParams['page']));
                        $page->setRequest($request);
                        $page->setResponse($response);
                        $page->render();
                        $page->setResponse($response);
                        break;
                    case Mandrill::getApp()->routeKeys['redirect']:
                        $requestGet = $request->getGet();
                        $url = $requestGet[Mandrill::getApp()->routeKeys['redirect']];
                        MRequest::redirect($url);
                        break;
                    default:
                        break;
                }
            } else if (file_exists($path.DS.'controllers'.DS.$request->getController().'.php')) {
                if ($request->isAdmin()){
                    $class = 'Admin'.ucfirst($request->getController()).'Controller';
                } else {
                    $class = ucfirst($request->getController()).'Controller';
                }
                $action = $request->getAction().'Action';
                if (method_exists($class, $action)) {
                    $ctrl = new $class($request,$response);
                    $ctrl->$action();
                    $moduleClass::setResponse($ctrl->getResponse());
                } else {
                    throw new MException(MTranslator::translate('mandrill.web.dispatcher.actionNotExists',array('module'=>$request->getModule(),'controller'=>$request->getController(),'action'=>$request->getAction())), '404');
                }
            } else {
                throw new MException(MTranslator::translate('mandrill.web.dispatcher.controllerNotExists',array('module'=>$request->getModule(),'controller'=>$request->getController())), '404');
            }
        } else {
            throw new MException(MTranslator::translate('mandrill.web.dispatcher.moduleNotExists',array('module'=>$request->getModule())), '404');
        }
    }
    
}
?>
